package com.xyhy.core.web.model.wrapper;

import java.io.Serializable;
import java.util.List;
import java.util.Optional;

import org.springframework.http.HttpStatus;

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

/**
 * @author Fire Team - Robert
 * @Description 数据返回包装类
 * @date 2020年12月14日
 */
@Data
public class Result<T> implements Serializable {
  private static final long serialVersionUID = 1L;

  @ApiModelProperty(value = "状态码", required = true)
  private int code;

  @ApiModelProperty(value = "承载数据")
  private T data;

  @ApiModelProperty(value = "返回消息", required = true)
  private String message = "操作成功!";

  @ApiModelProperty(value = "错误信息")
  private String error;

  @ApiModelProperty(value = "错误字段")
  private List<FieldError> errorFields;


  public static <E> Result<E> create() {
    return new Result<>();
  }

  public static <E> Result<E> success(String message) {
    Result<E> result = Result.create();
    result.setCode(HttpStatus.OK.value());
    result.setMessage(message);
    return result;
  }

  public static <E> Result<E> success(E data) {
    return success(data, null);
  }

  public static <E> Result<E> success(E data, String message) {
    Result<E> result = Result.create();
    result.ok(data);
    result.setCode(Optional.ofNullable(data).map(x -> HttpStatus.OK.value()).orElse(HttpStatus.NO_CONTENT.value()));
    Optional.ofNullable(message).ifPresent(x -> result.setMessage(x));
    return result;
  }

  public static <E> Result<E> fail(IResultCode iResultCode) {
    return fail(iResultCode.getCode(), iResultCode.getMessage(), null);
  }

  public static <E> Result<E> fail(IResultCode iResultCode, Exception exception) {
    return fail(iResultCode.getCode(), iResultCode.getMessage(), exception);
  }

  public static <E> Result<E> fail(IResultCode iResultCode, Throwable exception) {
    return fail(iResultCode.getCode(), iResultCode.getMessage(), exception);
  }

  public static <E> Result<E> fail(HttpStatus httpStatus) {
    return fail(httpStatus.value());
  }

  public static <E> Result<E> fail(int code) {
    return fail(code, null, null);
  }

  public static <E> Result<E> fail(HttpStatus httpStatus, String message) {
    return fail(httpStatus.value(), message, null);
  }

  public static <E> Result<E> fail(IResultCode iResultCode, Exception exception, List<FieldError> errorFields) {
    return new Result<E>().error(iResultCode.getCode(), iResultCode.getMessage(), null, null, errorFields);
  }

  public static <E> Result<E> fail(IResultCode iResultCode, E data) {
    return new Result<E>().error(iResultCode.getCode(), iResultCode.getMessage(), null, data, null);
  }

  public static <E> Result<E> fail(int code, String message) {
    return new Result<E>().error(code, message, null);
  }

  public static <E> Result<E> fail(int code, String message, Exception exception) {
    return new Result<E>().error(code, message, exception);
  }

  public static <E> Result<E> fail(int code, String message, Throwable exception) {
    return new Result<E>().error(code, message, exception);
  }

  public Result<T> ok(T data) {
    this.setData(data);
    return this;
  }

  public Result<T> error(int code, String message, Throwable exception) {
    return this.error(code, message, exception, null, null);
  }

  public Result<T> error(int code, String message, Throwable exception, T data, List<FieldError> errorFields) {
    this.code = code;
    this.message = message;
    this.data = data;
    this.error = Optional.ofNullable(exception).map(x -> x.getMessage()).orElse(message);
    this.errorFields = errorFields;
    return this;
  }

}
